//基于数组实现阻塞队列
//1.先实现一个普通队列
//2.线程安全
//3.加上阻塞功能

class MyBlockingQue{
    //模拟实现阻塞队列
    private int[] elem = new int[1000];
    //约定队列的有效元素
    //加上volatile防止读操作出现问题
    volatile private int head;
    volatile private int tail;
    //定义一个元素个数来判断队列是否满
    volatile private int usedsize;
    //入队列
    //加锁针对线程安全问题
   synchronized public void put(int val) throws InterruptedException {
        while (usedsize == elem.length){
            //队列满了,wait进行等待
            this.wait();
            //return;
        }
        elem[tail] = val;
        tail++;
        //如果tail达到数组末尾，让tail重新开始、
        if(tail == elem.length){
            tail = 0;
        }
        //可读性不高
//        tail = tail % elem.length;
        usedsize++;
        //在此处唤醒出队列且队列为空的线程
       this.notify();

    }
    //出队列
    synchronized public Integer take() throws InterruptedException {
        while (usedsize == 0){
            //如果队列为空,要进行阻塞等待
            this.wait();
            //return null;
        }
        int value = elem[head];
        head++;
        if(head == elem.length){
            head = 0;
        }
        usedsize--;
        //在此处唤醒等待中的线程
        this.notify();
        return value;
    }
    //队列不可能同时阻塞,一个队列不可能既是空,又是满
}
public class ThreadDemo {
    public static void main(String[] args) {
        MyBlockingQue myBlockingQue  = new MyBlockingQue();
        //消费者模型
        Thread t1 = new Thread(()->{
            while (true){
                try {
                    int value = myBlockingQue.take();
                    System.out.println("消费:" + value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //生产者模型
        t1.start();
        Thread t2 = new Thread(()->{
            int val = 0;
            while (true){
                try {
                    System.out.println("生产:"+ val);
                    myBlockingQue.put(val);
                    Thread.sleep(1000);
                    val++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        t2.start();
    }
}
